package com.im.service.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.im.codec.pack.user.UserCustomStatusChangeNotifyPack;
import com.im.codec.pack.user.UserStatusChangeNotifyPack;
import com.im.common.constant.Constants;
import com.im.common.enums.command.UserEventCommand;
import com.im.common.model.ClientInfo;
import com.im.common.model.UserSession;
import com.im.service.friendship.service.ImFriendService;
import com.im.service.user.model.UserStatusChangeNotifyContent;
import com.im.service.user.model.param.PullFriendOnlineStatusReq;
import com.im.service.user.model.param.PullUserOnlineStatusReq;
import com.im.service.user.model.param.SetUserCustomerStatusReq;
import com.im.service.user.model.param.SubscribeUserOnlineStatusReq;
import com.im.service.user.model.result.UserOnlineStatusResp;
import com.im.service.user.service.ImUserStatusService;
import com.im.service.utils.MessageProducer;
import com.im.service.utils.UserSessionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
public class ImUserStatusServiceImpl implements ImUserStatusService {

    @Autowired
    private UserSessionUtils userSessionUtils;
    @Autowired
    private MessageProducer messageProducer;
    @Autowired
    private ImFriendService imFriendService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void processUserOnlineStatusNotify(UserStatusChangeNotifyContent content) {
        // 获取用户会话信息
        List<UserSession> userSession = userSessionUtils.getUserSession(content.getAppId(), content.getUserId());
        UserStatusChangeNotifyPack pack = new UserStatusChangeNotifyPack();
        BeanUtils.copyProperties(content, pack);
        pack.setClient(userSession);
        // 同步在线状态给自己的其他端
        syncSender(pack, content.getUserId(), content);
        // 同步在线状态给好友和订阅的人
        dispatcher(pack, content.getUserId(), content.getAppId());
    }

    private void syncSender(Object pack, String userId, ClientInfo clientInfo) {
        // 发送用户在线状态变更通知同步消息
        messageProducer.sendToUserExceptClient(userId, UserEventCommand.USER_ONLINE_STATUS_CHANGE_NOTIFY_SYNC, pack, clientInfo);
    }

    private void dispatcher(Object pack, String userId, Integer appId) {
        // 获取用户的所有好友ID
        List<String> allFriendId = imFriendService.getAllFriendId(userId, appId);
        for (String fid : allFriendId) {
            // 发送用户在线状态变更通知消息给好友
            messageProducer.sendToUser(fid, UserEventCommand.USER_ONLINE_STATUS_CHANGE_NOTIFY, pack, appId);
        }
        String userKey = appId + ":" + Constants.RedisConstants.subscribe + userId;
        Set<Object> keys = stringRedisTemplate.opsForHash().keys(userKey);
        for (Object key : keys) {
            String filed = (String) key;
            Long expire = Long.valueOf((String) stringRedisTemplate.opsForHash().get(userKey, filed));
            if (expire > 0 && expire > System.currentTimeMillis()) {
                // 发送用户在线状态变更通知消息给订阅者
                messageProducer.sendToUser(filed, UserEventCommand.USER_ONLINE_STATUS_CHANGE_NOTIFY, pack, appId);
            } else {
                stringRedisTemplate.opsForHash().delete(userKey, filed);
            }
        }
    }

    @Override
    public void subscribeUserOnlineStatus(SubscribeUserOnlineStatusReq req) {
        // 计算订阅过期时间
        Long subExpireTime = 0L;
        if (req != null && req.getSubTime() > 0) {
            subExpireTime = System.currentTimeMillis() + req.getSubTime();
        }
        // 遍历订阅的用户ID列表，并将订阅信息存储到Redis中
        for (String beSubUserId : req.getSubUserId()) {
            String userKey = req.getAppId() + ":" + Constants.RedisConstants.subscribe + ":" + beSubUserId;
            stringRedisTemplate.opsForHash().put(userKey, req.getOperator(), subExpireTime.toString());
        }
    }

    @Override
    public void setUserCustomerStatus(SetUserCustomerStatusReq req) {
        UserCustomStatusChangeNotifyPack pack = new UserCustomStatusChangeNotifyPack();
        pack.setCustomStatus(req.getCustomStatus());
        pack.setCustomText(req.getCustomText());
        pack.setUserId(req.getUserId());
        String userKey = req.getAppId() + ":" + Constants.RedisConstants.userCustomerStatus + ":" + req.getUserId();
        // 在Redis中设置用户客服状态信息
        stringRedisTemplate.opsForValue().set(userKey, JSONObject.toJSONString(pack));
        // 发送用户状态变更通知给其他端
        syncSender(pack, req.getUserId(), new ClientInfo(req.getAppId(), req.getClientType(), req.getImei()));
        // 分发用户状态变更通知给好友
        dispatcher(pack, req.getUserId(), req.getAppId());
    }

    @Override
    public Map<String, UserOnlineStatusResp> queryFriendOnlineStatus(PullFriendOnlineStatusReq req) {
        // 获取用户的所有好友ID
        List<String> allFriendId = imFriendService.getAllFriendId(req.getOperator(), req.getAppId());
        return getUserOnlineStatus(allFriendId, req.getAppId());
    }

    @Override
    public Map<String, UserOnlineStatusResp> queryUserOnlineStatus(PullUserOnlineStatusReq req) {
        return getUserOnlineStatus(req.getUserList(), req.getAppId());
    }

    private Map<String, UserOnlineStatusResp> getUserOnlineStatus(List<String> userId, Integer appId) {
        Map<String, UserOnlineStatusResp> result = new HashMap<>(userId.size());
        for (String uid : userId) {
            UserOnlineStatusResp resp = new UserOnlineStatusResp();
            List<UserSession> userSession = userSessionUtils.getUserSession(appId, uid);
            resp.setSession(userSession);
            String userKey = appId + ":" + Constants.RedisConstants.userCustomerStatus + ":" + uid;
            String s = stringRedisTemplate.opsForValue().get(userKey);
            if (StringUtils.isNotBlank(s)) {
                JSONObject parse = (JSONObject) JSON.parse(s);
                resp.setCustomText(parse.getString("customText"));
                resp.setCustomStatus(parse.getInteger("customStatus"));
            }
            result.put(uid, resp);
        }
        return result;
    }

}
